package com.maslyk.invitation.service;

import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;

import com.maslyk.configuration.DataCache;
import com.maslyk.invitation.entitybean.Attachment;
import com.maslyk.invitation.entitybean.Auditlog;
import com.maslyk.invitation.entitybean.Comment;
import com.maslyk.invitation.entitybean.FeeInvitation;
import com.maslyk.invitation.entitybean.Insertion;
import com.maslyk.invitation.entitybean.Invitation;
import com.maslyk.invitation.entitybean.Order;
import com.maslyk.invitation.entitybean.Person;
import com.maslyk.invitation.entitybean.PriceParameter;
import com.maslyk.invitation.entitybean.Product;
import com.maslyk.invitation.entitybean.Salesman;
import com.maslyk.invitation.entitybean.Text;
import com.maslyk.invitation.entitybean.Vigniette;
import com.maslyk.invitation.entitybean.util.CloneUtil;
import com.maslyk.invitation.enums.LocalNames;
import com.maslyk.invitation.enums.RecordTypeEnum;
import com.maslyk.invitation.exception.LogicalException;
import com.maslyk.invitation.service.email.MessagingEmailService;
import com.maslyk.invitation.to.AuditLogSearchCriteria;
import com.maslyk.invitation.to.OrderSearchCondition;


public class PersistenceService implements IOrderService
{
	Logger log = Logger.getLogger(PersistenceService.class);
	
	private EntityManagerFactory emf = null;
	
	private static PersistenceService instance;

    private PersistenceService()
    {
    	emf = Persistence.createEntityManagerFactory("InvitationPU");
    }
    
    public synchronized static PersistenceService getInstance()
    {
    	if(instance == null)
    		instance = new PersistenceService();
    	return instance;	
    }
    
    public EntityManager getEntityManager()
    {
    	if(!emf.isOpen())
    		emf = Persistence.createEntityManagerFactory("InvitationPU");
    	
    	EntityManager em = emf.createEntityManager();
    	return em;
    }

    public Person createPerson(Person personEntity)
    {
        return null;
    }

    public Salesman createSalesman(Salesman salesmanEntity) throws LogicalException, Exception
    {
        String passwd = salesmanEntity.getPassword();
        
        EntityManager em = getEntityManager();
        
        try
        {
            salesmanEntity.setPassword(MD5Service.generateHexString(salesmanEntity.getPassword()));
            em.getTransaction().begin();
            em.persist(salesmanEntity);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            getEntityManager().getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }

        StringBuffer message = new StringBuffer();
        message.append("<h2>"+salesmanEntity.getPersonid().getFirstname()+",</h2>");
        message.append("<h3>Za\u0142o\u017Cono Ci nowe konto w systemie rejestracji zam\u00f3wien  StudioGrafic</h3>");
        message.append("<h4>Nazwa u\u017Cytkownika (login): " + salesmanEntity.getLogin() + "</h4>");
        message.append("<h4>Has\u0142o do systemu to: " +passwd+"</h4>");
        message.append("<br /><br />");
        message.append("<i>Zapamietaj prosze te informacje.</i>");
        MessagingEmailService emailService = new MessagingEmailService();
        emailService.sendMessage(salesmanEntity.getPersonid().getEmail(), message.toString(), "Dodano nowego u\u017Cytkownika systemu");
        
        return salesmanEntity;
    }

    public Salesman editSalesman(Salesman salesmanEntity) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {

            em.getTransaction().begin();
            salesmanEntity = em.merge(salesmanEntity);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
        return salesmanEntity;
    }

    public void destroySalesman(Salesman salesmanEntity) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            Salesman salesmanEntity1 = em.getReference(Salesman.class, salesmanEntity.getId());
            em.remove(salesmanEntity1);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
    }
    
    public void removePriceParameter(PriceParameter priceParameter) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            PriceParameter priceParameterFound = em.getReference(PriceParameter.class, priceParameter.getId());
            em.remove(priceParameterFound);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
    }

    public Person findPersonEntity(Integer id) throws Exception
    {
    	EntityManager em = getEntityManager();
    	try
    	{
    		return em.find(Person.class, id);
    	}
    	catch(Exception ex)
    	{
    		throw ex;
    	}
        finally
        {
        	em.close();
        }
    }
    
    public Order findOrderEntity(Integer id) throws Exception
    {
    	EntityManager em = getEntityManager();
    	try
    	{
    		return em.find(Order.class, id);
    	}
    	catch(Exception ex)
    	{
    		throw ex;
    	}
    }

    public Salesman findSalesmanEntity(Integer id) throws Exception
    {
    	EntityManager em = getEntityManager();
    	try
    	{
    		return em.find(Salesman.class, id);
    	}
    	catch(Exception e)
    	{
    		throw e;
    	}
        finally
        {
        	em.close();
        }
    }

    @SuppressWarnings("unchecked")
	public List<Salesman> getSalesmanList() throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {
        	return em.createQuery("select o from Salesman o order by o.personid.surname").getResultList();
        }
        catch(Exception e)
        {
        	throw e;
        }
        finally
        {
        	em.close();
        }
    }

    public Text createText(Text textEntity) throws Exception
    {
    	EntityManager em = getEntityManager();
    	
        try
        {
            em.getTransaction().begin();
            em.persist(textEntity);
            em.flush();
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
        return textEntity;
    }
    
    public Attachment createAttachment(Attachment attachmentEntity) throws Exception
    {
    	EntityManager em = getEntityManager();
    	
        try
        {
            em.getTransaction().begin();
            em.persist(attachmentEntity);
            em.flush();
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
        return attachmentEntity;
    }

    public PriceParameter createPriceParameter(PriceParameter priceParameterEntity) throws Exception
    {
    	EntityManager em = getEntityManager();
    	
        try
        {
            em.getTransaction().begin();
            em.persist(priceParameterEntity);
            em.flush();
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
        return priceParameterEntity;
    }

    
    public Text editText(Text textEntity) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            textEntity = em.merge(textEntity);
            em.flush();
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
        return textEntity;
    }

    public PriceParameter updatePriceParameter(PriceParameter priceParameterEntity) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            priceParameterEntity = em.merge(priceParameterEntity);
            em.flush();
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
        return priceParameterEntity;
    }
    
    public Invitation updateInvitation(Invitation inv) throws Exception {
    	
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            inv = em.merge(inv);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
        return inv;
    }
    
    public FeeInvitation updateFeeInvitation(FeeInvitation fee) throws Exception {
    	
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            fee = em.merge(fee);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
        return fee;
    }
    
    @SuppressWarnings("unchecked")
	public void destroyText(Text textEntity) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            textEntity = em.getReference(Text.class, textEntity.getId());
            em.remove(textEntity);
            em.getTransaction().commit();
            ((List<Text>) DataCache.getInstance().getCache().get(LocalNames.TEXT_LIST)).remove(textEntity);
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
    }

	public void removeFeeInvotation(FeeInvitation fee) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            fee = em.getReference(FeeInvitation.class, fee.getId());
            em.remove(fee);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
    }

    @SuppressWarnings("unchecked")
	public List<Text> getTextList()
    {
    	EntityManager em = getEntityManager();
        List<Text> texts = null;

        Query q = em.createQuery("select object(o) from Text as o");
        texts = q.getResultList();

        return texts;
    }
    
	@SuppressWarnings("unchecked")
	public List<PriceParameter> getPriceParameterList()
    {
    	EntityManager em = getEntityManager();
        List<PriceParameter> priceParameterList = null;

        Query q = em.createQuery("select o from PriceParameter as o");
        priceParameterList = q.getResultList();

        return priceParameterList;
    }
    
    @SuppressWarnings("unchecked")
	public List<Attachment> getAttachmentList(int position)
    {
    	EntityManager em = getEntityManager();
        List<Attachment> atts = null;

        Query q = em.createQuery("select o from Attachment o");
        q.setFirstResult(position);
        q.setMaxResults(100);
        atts = q.getResultList();

        return atts;
    }

	@SuppressWarnings("unchecked")
	public List<Auditlog> getAuditList(AuditLogSearchCriteria auditCriteria)
    {
    	EntityManager em = getEntityManager();
        List<Auditlog> logs = null;

        Query q = em.createQuery("select a from Auditlog a where a.operatorId = :operator and a.objectKey = :key and date(a.createdDate) between :from and :to order by a.entityId");
        q.setParameter("operator", auditCriteria.getSalesman());
        q.setParameter("key", auditCriteria.getSearchKey());
        q.setParameter("from", auditCriteria.getDateFrom());
        q.setParameter("to", auditCriteria.getDateTo());
        logs = q.getResultList();

        return logs;
    }

    
    public Text findTextEntity(Integer id)
    {
    	EntityManager em = getEntityManager();
    	return em.find(Text.class, id);
    }

    public Salesman login(String login, String password)
    {
    	EntityManager em = getEntityManager();
        Query qry = em.createQuery("from Salesman salesman where salesman.login = :login and salesman.password = :password");
        qry.setParameter("login", login);
        qry.setParameter("password", MD5Service.generateHexString(password));

        Salesman logger = null;
        
        try
        {
        	logger = (Salesman) qry.getSingleResult();
        }
        catch (Throwable t)
        {
            log.error("Blad logowania operatora: \n\n", t);
        	return null;
        }
        finally
        {
        	em.close();
        }
        
        // nieaktywny nie moze sie zalogowac
        if(logger.isInactive())
        	return null;
        
        return logger;
    }

    public Order saveOrder(Order order) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {   
        	em.getTransaction().begin();

            if(order.getId() == null)
                em.persist(order);
            else
                em.merge(order);

            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
        return order;
    }

    @SuppressWarnings("unchecked")
	public List<Order> searchOrders(OrderSearchCondition condition)
    {
    	EntityManager em = getEntityManager();
        Session session = (Session) em.getDelegate();
        Criteria criteria = session.createCriteria(Order.class);
        
        if(!condition.isSearchInOffers())
        	criteria.add(Restrictions.eq("type", RecordTypeEnum.ORDER));

        if(condition.getNumber() != null)
            criteria.add(Restrictions.like("number", condition.getNumber()+"%"));

        if(condition.getClientName() != null)
            criteria.add(Restrictions.like("clientName", "%" + condition.getClientName() + "%"));

        if(condition.getEmail() != null)
            criteria.add(Restrictions.like("email", "%" + condition.getEmail() + "%"));

        Criteria invitationCriteria = null;

        if(condition.getBrideName() != null ||
           condition.getBrideGroom() != null ||
           condition.getWeddingpartyplace() != null ||
           condition.getWeddingplace() != null)
        {
            invitationCriteria = criteria.createCriteria("invitationEntityCollection");
        }

        if(condition.getBrideName() != null)
            invitationCriteria.add(Restrictions.like("bridename", "%"+condition.getBrideName()+"%"));

        if(condition.getBrideGroom() != null)
            invitationCriteria.add(Restrictions.like("bridegroom", "%"+condition.getBrideGroom()+"%"));

        if(condition.getWeddingpartyplace() != null)
            invitationCriteria.add(Restrictions.like("weddingpartyplace", "%"+condition.getWeddingpartyplace()+"%"));

        if(condition.getWeddingplace() != null)
            invitationCriteria.add(Restrictions.like("weddingplace", "%"+condition.getWeddingplace()+"%"));
        
        
        
        if(condition.getProduct() != null)
        {
        	Criteria productCriteria = null;
        	productCriteria = criteria.createCriteria("productCollection");
        	productCriteria.add(Restrictions.like("code", "%"+condition.getProduct()+"%"));
        }

        if(condition.getSalesmanResponsible() != null)
        {
            criteria.createCriteria("responsible").add(Restrictions.eq("id", condition.getSalesmanResponsible().getId()));
        }

        if(!condition.getStatus().isEmpty())
            criteria.add(Restrictions.in("status", condition.getStatus()));
        
        if(!condition.getAdditionalStatus().isEmpty())
            criteria.add(Restrictions.in("additionalStatus", condition.getAdditionalStatus()));

        return (List<Order>)criteria.list();
    }

    public void removeOrder(Order order) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            Order orderTmp = em.getReference(Order.class, order.getId());
            em.remove(orderTmp);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
    }

    public void refreshEntity(Object obj)
    {
    	EntityManager em = getEntityManager();
        em.refresh(obj);
    }

    public boolean containsEntity(Object obj)
    {
    	EntityManager em = getEntityManager();
        return em.contains(obj);
    }

    public void removeInvitation(Invitation invitationEntity) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            invitationEntity = em.getReference(Invitation.class, invitationEntity.getId());
            em.remove(invitationEntity);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
    }

    public void removeInsertion(Insertion insertion) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            insertion = em.getReference(Insertion.class, insertion.getId());
            em.remove(insertion);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
    }
    
    public void removeComment(Comment comment) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            comment = em.getReference(Comment.class, comment.getId());
            em.remove(comment);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
    }

    public void removeProduct(Product product) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            product = em.getReference(Product.class, product.getId());
            em.remove(product);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
    }

    public void removeVigniette(Vigniette vigniette) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            vigniette = em.getReference(Vigniette.class, vigniette.getId());
            em.remove(vigniette);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
    }
    
    public void removeAttachment(Attachment attachment) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            attachment = em.getReference(Attachment.class, attachment.getId());
            em.remove(attachment);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
    }

    public Comment createComment(Comment comment) throws Exception
    {
    	EntityManager em = getEntityManager();
        try
        {
            em.getTransaction().begin();
            em.persist(comment);
            em.getTransaction().commit();
        }
        catch (Exception ex)
        {
            em.getTransaction().getRollbackOnly();
            throw ex;
        }
        finally
        {
        	em.close();
        }
        return comment;
    }
    
    public void changeOfferToOrder(Order ordr) throws Exception
    {
    	String newOrderNote = "To zamowienie powstalo z oferty: " + ordr.getNumber();
    	Order newOrder = null;
		newOrder = CloneUtil.cloneOrder(ordr);
		newOrder.setNumber("B");
		newOrder.setType(RecordTypeEnum.ORDER);
		newOrder = saveOrder(newOrder);
		
		String oldOrderNote = "Wygenerowano zamówienie " + newOrder.getNumber() + " z tej oferty";
		ordr.getCommentList().add(new Comment(null, ordr, ordr.getResponsible(),new Date(),oldOrderNote));
		newOrder.getCommentList().add(new Comment(null, newOrder, newOrder.getResponsible(),new Date(),newOrderNote));
		
		saveOrder(ordr);
		saveOrder(newOrder);
    }
}
